﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;

namespace 摸鱼
{
    public class 鼠标轨迹模拟
    {
        private Random 随机数 = new Random();
        private Point 上一次位置;
        private Point 实际当前位置;

        public void 人类方式移动(Point 起点, Point 终点, int 总移动时间, int 随机定位半径)
        {
            实际当前位置 = 起点;
            上一次位置 = 起点;

            // 人类移动时间会有±20%的随机变化
            int 实际总时间 = Math.Max(总移动时间, 100); // 限制最少移动时间
            实际总时间 = (int)(实际总时间 * (0.8 + 随机数.NextDouble() * 0.4));

            //模拟人类快速移动鼠标的定位误差, 距离越远移动速度越快误差越大
            double 起点到终点距离 = 计算距离(起点, 终点);

            // 模拟人类快速移动鼠标的定位误差
            double 角度 = 随机数.NextDouble() * 2 * Math.PI;
            double 距离 = 计算速度误差(起点到终点距离, 实际总时间);
            Point 偏差终点 = new Point(
                终点.X + (int)(距离 * Math.Cos(角度)),
                终点.Y + (int)(距离 * Math.Sin(角度))
            );

            // 主要移动阶段 - 只在接近终点时过冲
            int 剩余时间 = 执行主要移动阶段(起点, 偏差终点, 实际总时间);

            Console.WriteLine($"主要移动结束");

            // 使用随机定位半径改变实际终点位置
            if (随机定位半径 > 0)
            {
                角度 = 随机数.NextDouble() * 2 * Math.PI;
                距离 = 随机数.NextDouble() * 随机定位半径;

                终点 = new Point(
                    终点.X + (int)(距离 * Math.Cos(角度)),
                    终点.Y + (int)(距离 * Math.Sin(角度))
                );
            }

            // 最终精确定位阶段
            执行人类最终定位(实际当前位置, 终点, 剩余时间);
        }

        private double 计算速度误差(double 距离, int 时间)
        {
            // 速度误差与移动速度和距离成正比
            double 平均速度 = 距离 / (时间 * 3);
            double 误差范围 = 平均速度 * 距离 * 0.1; // 基础误差范围

            double 最小误差 = 0;
            if (平均速度 > 2.92)
                最小误差 = 40;
            else if (平均速度 > 2.25)
                最小误差 = 30;
            else if (平均速度 > 1.73)
                最小误差 = 20;
            else if (平均速度 > 1.33)
                最小误差 = 10;
            return Math.Max(最小误差, Math.Min(误差范围, 200) * 随机数.NextDouble()); // 限制最大误差
        }

        private void 执行人类最终定位(Point 当前, Point 目标, int 剩余时间)
        {
            double 剩余距离 = 计算距离(当前, 目标);

            int 可用时间 = 0;

            // 如果过冲很严重，增加回退移动
            if (剩余距离 > 40)
            {
                可用时间 = (int)Math.Min(剩余距离 * 1.2, 300);
                执行精确微调移动(当前, 目标, 可用时间, 剩余距离 / 可用时间);
                当前 = 实际当前位置;
            }

            // 最终精确定位
            if (计算距离(当前, 目标) > 2)
            {
                可用时间 = 20;
                执行精确定位(当前, 目标, 可用时间, 剩余距离 / 可用时间);
            }

            // 确保最终到达目标
            if (计算距离(实际当前位置, 目标) > 1)
            {
                SetCursorPos(目标.X, 目标.Y);
                实际当前位置 = 目标;
            }
        }
        private void 执行精确定位(Point 当前, Point 目标, int 时间, double 当前速度)
        {
            int 移动次数 = (int)Math.Max(2, Math.Min(6, 8 - 当前速度 * 3));
            int 每次时间 = Math.Max(3, 时间 / 移动次数);

            double 总距离 = 计算距离(当前, 目标);
            if (总距离 <= 2) return;          // 已经到位

            for (int i = 1; i <= 移动次数; i++)
            {
                double 进度 = (double)i / 移动次数;

                // 直线插值
                int x = (int)Math.Round(当前.X + (目标.X - 当前.X) * 进度);
                int y = (int)Math.Round(当前.Y + (目标.Y - 当前.Y) * 进度);

                // 最多 ±1 像素的“人手”抖动
                x += 随机数.Next(-1, 2);
                y += 随机数.Next(-1, 2);

                SetCursorPos(x, y);
                实际当前位置 = new Point(x, y);

                if (每次时间 > 0)
                    MoyuDelay.Star(每次时间);

                // 提前退出
                if (计算距离(实际当前位置, 目标) <= 1.5) break;
            }
        }
        private int 执行主要移动阶段(Point 起点, Point 偏差终点, int 总移动时间)
        {
            Point 当前点 = 起点;
            double 总距离 = 计算距离(起点, 偏差终点);

            // 主要移动阶段占用大部分时间
            int 主要阶段时间 = (int)(总移动时间 * 0.85);
            主要阶段时间 = Math.Max(主要阶段时间, 50);

            // 根据距离决定分段数量
            int 分段数 = 计算分段数量(总距离);
            List<Point> 分段点 = 生成分段轨迹点(起点, 偏差终点, 分段数);

            // 执行分段移动
            int 每段时间 = 主要阶段时间 / 分段数;

            for (int i = 0; i < 分段点.Count - 1; i++)
            {
                Point 段起点 = i == 0 ? 起点 : 分段点[i];
                Point 段终点 = 分段点[i + 1];

                执行单段移动(段起点, 段终点, 每段时间);
                当前点 = 实际当前位置;
            }

            // 确保最终到达偏差终点
            if (计算距离(实际当前位置, 偏差终点) > 2)
            {
                SetCursorPos(偏差终点.X, 偏差终点.Y);
                实际当前位置 = 偏差终点;
            }

            return 总移动时间 - 主要阶段时间;
        }

        private int 计算分段数量(double 距离)
        {
            // 根据距离动态计算分段数量
            if (距离 < 50) return 1;
            if (距离 < 200) return 2;
            if (距离 < 500) return 3;
            return 4;
        }

        private List<Point> 生成分段轨迹点(Point 起点, Point 终点, int 分段数)
        {
            var 分段点 = new List<Point> { 起点 };

            if (分段数 == 1)
            {
                分段点.Add(终点);
                return 分段点;
            }

            // 计算基础方向向量
            double 基础角度 = Math.Atan2(终点.Y - 起点.Y, 终点.X - 起点.X);
            double 总距离 = 计算距离(起点, 终点);

            // 生成中间控制点（带有角度随机性）
            for (int i = 1; i < 分段数; i++)
            {
                double 进度 = (double)i / 分段数;

                // 应用角度随机性（±10°）
                double 角度偏移 = (随机数.NextDouble() - 0.5) * 20 * Math.PI / 180; // ±10度转弧度
                double 当前角度 = 基础角度 + 角度偏移;

                // 计算当前段的理想位置
                double 当前距离 = 总距离 * 进度;
                Point 理想点 = new Point(
                    (int)(起点.X + 当前距离 * Math.Cos(基础角度)),
                    (int)(起点.Y + 当前距离 * Math.Sin(基础角度))
                );

                // 应用角度偏移的实际位置
                double 偏移距离 = 总距离 * 0.1 * (0.5 + 随机数.NextDouble() * 0.5); // 5-10%的随机距离
                Point 控制点 = new Point(
                    (int)(理想点.X + 偏移距离 * Math.Cos(当前角度)),
                    (int)(理想点.Y + 偏移距离 * Math.Sin(当前角度))
                );

                分段点.Add(控制点);
            }

            分段点.Add(终点);
            return 分段点;
        }

        private List<Point> 生成人类轨迹(Point 起点, Point 终点, int 点数)
        {
            var 轨迹点 = new List<Point>();

            // 使用分段点生成更自然的贝塞尔曲线
            List<Point> 分段点 = 生成分段轨迹点(起点, 终点, 2); // 使用2个中间点

            if (分段点.Count == 2)
            {
                // 直接两点，使用简单控制点
                Point 控制点1 = 计算随机控制点(起点, 终点, 0.3);
                Point 控制点2 = 计算随机控制点(起点, 终点, 0.7);

                for (int i = 0; i <= 点数; i++)
                {
                    double t = (double)i / 点数;
                    Point 点 = 计算贝塞尔点(起点, 控制点1, 控制点2, 终点, t);
                    点 = 添加自然抖动(点, 上一次位置);
                    轨迹点.Add(点);
                    上一次位置 = 点;
                }
            }
            else
            {
                // 多段贝塞尔曲线
                for (int seg = 0; seg < 分段点.Count - 1; seg++)
                {
                    Point segStart = 分段点[seg];
                    Point segEnd = 分段点[seg + 1];
                    int segPoints = 点数 / (分段点.Count - 1);

                    Point 控制点1 = 计算随机控制点(segStart, segEnd, 0.3);
                    Point 控制点2 = 计算随机控制点(segStart, segEnd, 0.7);

                    for (int i = 0; i <= segPoints; i++)
                    {
                        double t = (double)i / segPoints;
                        Point 点 = 计算贝塞尔点(segStart, 控制点1, 控制点2, segEnd, t);

                        if (seg > 0 && i == 0) continue; // 避免重复点

                        点 = 添加自然抖动(点, 上一次位置);
                        轨迹点.Add(点);
                        上一次位置 = 点;
                    }
                }
            }

            return 轨迹点;
        }

        //private List<Point> 生成人类轨迹(Point 起点, Point 终点, int 点数)
        //{
        //    var 轨迹点 = new List<Point>();

        //    // 减少控制点随机性
        //    Point 控制点1 = 计算随机控制点(起点, 终点, 0.3);
        //    Point 控制点2 = 计算随机控制点(起点, 终点, 0.7);

        //    for (int i = 0; i <= 点数; i++)
        //    {
        //        double t = (double)i / 点数;
        //        Point 点 = 计算贝塞尔点(起点, 控制点1, 控制点2, 终点, t);

        //        // 减少抖动幅度
        //        点 = 添加自然抖动(点, 上一次位置);
        //        轨迹点.Add(点);
        //        上一次位置 = 点;
        //    }

        //    return 轨迹点;
        //}

        private double 缓动函数(double t)
        {
            // 缓动函数：开始慢，中间快，结尾慢
            return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
        }

        private void 执行单段移动(Point 起点, Point 终点, int 段移动时间)
        {
            int 点数 = Math.Max(2, 段移动时间 / 12); // 适当增加点数，让移动更平滑
            List<Point> 轨迹点 = 生成人类轨迹(起点, 终点, 点数);

            int 点延迟 = 段移动时间 / Math.Max(1, 轨迹点.Count);

            foreach (var 点 in 轨迹点)
            {
                SetCursorPos(点.X, 点.Y);
                实际当前位置 = 点;

                if (点延迟 > 0)
                    MoyuDelay.Star(点延迟);
            }
        }

        private Point 添加自然抖动(Point 点, Point 上一个点)
        {
            int dx = 点.X - 上一个点.X;
            int dy = 点.Y - 上一个点.Y;
            double 速度 = Math.Sqrt(dx * dx + dy * dy);

            // 减少最大抖动范围
            int 最大抖动 = (int)Math.Min(3, 1 + 速度 * 0.1);

            return new Point(
                点.X + 随机数.Next(-最大抖动, 最大抖动 + 1),
                点.Y + 随机数.Next(-最大抖动, 最大抖动 + 1)
            );
        }

        private Point 计算随机控制点(Point 起点, Point 终点, double 比例)
        {
            int dx = 终点.X - 起点.X;
            int dy = 终点.Y - 起点.Y;

            // 减少控制点偏移量
            int 偏移量X = (int)(dx * 0.2 * (随机数.NextDouble() - 0.5));
            int 偏移量Y = (int)(dy * 0.2 * (随机数.NextDouble() - 0.5));

            return new Point(
                起点.X + (int)(dx * 比例) + 偏移量X,
                起点.Y + (int)(dy * 比例) + 偏移量Y
            );
        }

        private double 计算距离(Point p1, Point p2)
        {
            return Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));
        }

        private Point 计算贝塞尔点(Point p0, Point p1, Point p2, Point p3, double t)
        {
            double u = 1 - t;
            double uu = u * u;
            double uuu = uu * u;
            double tt = t * t;
            double ttt = tt * t;

            double x = uuu * p0.X + 3 * uu * t * p1.X + 3 * u * tt * p2.X + ttt * p3.X;
            double y = uuu * p0.Y + 3 * uu * t * p1.Y + 3 * u * tt * p2.Y + ttt * p3.Y;

            return new Point((int)x, (int)y);
        }

        private void 执行精确微调移动(Point 当前, Point 目标, int 时间, double 当前速度)
        {
            // 增加移动次数，让精确定位更细腻
            int 移动次数 = (int)Math.Max(2, Math.Min(6, 8 - 当前速度 * 3));

            int 每次时间 = Math.Max(3, 时间 / 移动次数);

            double 初始距离 = 计算距离(当前, 目标);

            for (int i = 0; i < 移动次数; i++)
            {
                Point 下一个点;
                double 进度 = (double)(i + 1) / 移动次数;

                double 缓动进度 = 缓动函数(进度);

                下一个点 = new Point(
                    当前.X + (int)((目标.X - 当前.X) * 缓动进度),
                    当前.Y + (int)((目标.Y - 当前.Y) * 缓动进度)
                );

                // 减少最终抖动的幅度
                if (i == 移动次数 - 1 && 初始距离 < 15)
                {
                    下一个点 = new Point(
                        下一个点.X + 随机数.Next(-1, 2),
                        下一个点.Y + 随机数.Next(-1, 2)
                    );
                }

                执行单段移动(当前, 下一个点, 每次时间);
                当前 = 实际当前位置;

                if (计算距离(当前, 目标) < 1.5)
                    break;
            }
        }

        private static void SetCursorPos(int X, int Y)
        {
            Cursor.Position = new Point(X, Y);
        }
    }
}